package com.wuyu.mini.spring.aop.aspect;

import com.wuyu.mini.spring.annotation.MiniAspect;
import com.wuyu.mini.spring.annotation.MiniOrder;
import com.wuyu.mini.spring.ioc.factory.MiniBeanFactory;
import com.wuyu.mini.spring.util.MiniValidUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * 切面织入器
 */
public class MiniAspectWeaver {
    /**
     * 拥有一个Bean容器
     */
    private MiniBeanFactory miniBeanFactory;

    public MiniAspectWeaver(){
        miniBeanFactory = MiniBeanFactory.MiniBeanFactoryHolder.SINGLETON.getInstance();
    }

    /**
     * 1.获取所有的切面类
     * 2.遍历容器里的类
     * 3.筛选出匹配类的切面aspect
     * 4.尝试进行Aspect的织入 生成动态代理对象
     */
    public void doAop() {
        //1.获取所有的切面类
        Set<Class<?>> aspectSet = miniBeanFactory.getClassesByAnnotation(MiniAspect.class);
        if(MiniValidUtil.isEmpty(aspectSet)){return;}
        //2.拼装AspectInfoList
        List<MiniAspectInfo> aspectInfoList = packAspectInfoList(aspectSet);
        //3.遍历容器里的类
        Set<Class<?>> classSet = miniBeanFactory.getClasses();
        for (Class<?> targetClass: classSet) {
            //排除AspectClass自身
            if(targetClass.isAnnotationPresent(MiniAspect.class)){
                continue;
            }
            //4.粗筛符合条件的Aspect
            List<MiniAspectInfo> roughMatchedAspectList  = collectRoughMatchedAspectListForSpecificClass(aspectInfoList, targetClass);
            //5.尝试进行Aspect的织入
            wrapIfNecessary(roughMatchedAspectList,targetClass);
        }
    }

    private List<MiniAspectInfo> collectRoughMatchedAspectListForSpecificClass(List<MiniAspectInfo> aspectInfoList, Class<?> targetClass) {
        List<MiniAspectInfo> roughMatchedAspectList = new ArrayList<>();
        for(MiniAspectInfo aspectInfo : aspectInfoList){
            //粗筛
            if(aspectInfo.getPointcutLocator().roughMatches(targetClass)){
                roughMatchedAspectList.add(aspectInfo);
            }
        }
        return roughMatchedAspectList;
    }

    private List<MiniAspectInfo> packAspectInfoList(Set<Class<?>> aspectSet) {
        List<MiniAspectInfo> aspectInfoList = new ArrayList<>();
        for(Class<?> aspectClass : aspectSet){
            if (verifyAspect(aspectClass)){
                MiniOrder orderTag = aspectClass.getAnnotation(MiniOrder.class);
                MiniAspect aspectTag = aspectClass.getAnnotation(MiniAspect.class);
                MiniDefaultAspect defaultAspect = (MiniDefaultAspect) miniBeanFactory.getBean(aspectClass);
                //初始化表达式定位器
                MiniPointcutLocator pointcutLocator = new MiniPointcutLocator(aspectTag.pointcut());
                MiniAspectInfo aspectInfo = new MiniAspectInfo(orderTag.value(), defaultAspect, pointcutLocator);
                aspectInfoList.add(aspectInfo);
            } else {
                //不遵守规范则直接抛出异常
                throw new RuntimeException("@Aspect and @Order must be added to the Aspect class, and Aspect class must extend from DefaultAspect");
            }
        }
        return aspectInfoList;
    }
    /**
    框架中一定要遵守给Aspect类添加@Aspect和@Order标签的规范，同时，必须继承自DefaultAspect.class
    此外，@Aspect的属性值不能是它本身
     */
    private boolean verifyAspect(Class<?> aspectClass) {
        return aspectClass.isAnnotationPresent(MiniAspect.class) &&
                aspectClass.isAnnotationPresent(MiniOrder.class) &&
                MiniDefaultAspect.class.isAssignableFrom(aspectClass);
    }

    private void wrapIfNecessary(List<MiniAspectInfo> roughMatchedAspectList, Class<?> targetClass) {
        if(MiniValidUtil.isEmpty(roughMatchedAspectList)){return;}
        //创建动态代理对象
        MiniAspectListExecutor aspectListExecutor = new MiniAspectListExecutor(targetClass, roughMatchedAspectList);
        Object proxyBean = MiniProxyCreator.createProxy(targetClass, aspectListExecutor);
        miniBeanFactory.addBean(targetClass, proxyBean);
    }


}
